// ChildView.cpp : implementation of the CChildView class
// Author:	Dani Brunstein, 3/11/2001
//			Computer Graphics
// Send bugs to: danikoz@cs.technion.ac.il
//

#include "stdafx.h"
#include "CGWork.h"
#include "ChildView.h"
#include "SensDialog.h"
#include "ProjectionPlainDialog.h"
#include "MatPropsDlg.h"
#include "LightSourcesDlg.h"

// Dialog boxes include
#include "renderToFile.h" 
#include "MaterialPropertiesDlg.h"
#include "LightDirectionDlg.h"
#include "MemDC.h"
#include "wrl.h"
#include "vrutil.h"
#include "CallbackObject.h"
#include "OurCallbackObject.h"
#include "PngWrapper.h"
#include <iostream>
#include <cmath>
using std::cout;
using std::endl;

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// For Status Bar access
#include "MainFrm.h"

/////////////////////////////////////////////////////////////////////////////
// CChildView

CChildView::CChildView()
{
	// Set default values
	m_nAxis = ID_AXIS_X;
	m_nAction = ID_ACTION_ROTATE;
	m_nView = ID_VIEW_ORTHOGRAPHIC;
	m_strDataFileName = "";
	
	m_bBackFaceCulling = false;
	m_bBackgroundImage = false;
	m_bIsPerspective = false;
	
	m_bNormalPerFace = false;
	m_bNormalPerVertex = false;
	m_bNormalReverse = false;
	
	m_viewOctTree = false;

	m_iBkgColor = RGB(255,255,255);

	m_nLightShading = ID_LIGHT_SHADING_FLAT;

	m_lMaterialAmbient = 0.2;
	m_lMaterialDiffuse = 0.8;
	m_lMaterialSpecular = 1.0;
	m_nMaterialCosineFactor = 32;

	m_nArrLightDirection[0] = 0;	// Light in direction of 0,0,-1 into the screen
	m_nArrLightDirection[1] = 0;
	m_nArrLightDirection[2] = -1;


	//initializing view matrix
	m_nProjectionPlane = nMaxProjectionPlane;
	m_bIsPerspective = false;
	m_bIsObjectSpace = false;
	m_bDrawBoundingBox = false;
	m_nWireColor = RGB(0,0,0);
	m_bViewAxes = false;


	m_dbAlpha = 50;

	m_PerspectiveMatrix[2][2] = m_nProjectionPlane/(m_nProjectionPlane-m_dbAlpha);
	m_PerspectiveMatrix[2][3]=1.0/m_nProjectionPlane;

	m_PerspectiveMatrix[3][0]=0;
	m_PerspectiveMatrix[3][1]=0;
	m_PerspectiveMatrix[3][2]=(-m_dbAlpha*m_nProjectionPlane)/(m_nProjectionPlane-m_dbAlpha);
	m_PerspectiveMatrix[3][3]=0;

	m_dbMouseSensetivity = 1.4 ;

	m_model.SetAmbientFactor(0.21);
	m_model.SetDiffuseFactor(0.41);
	m_model.SetSpecularFactor(0.41);
	m_model.SetCosineFactor(32);

	m_bShouldRender = false;

	Matrix3D Light0(1,4,true);
	Light0[0][2] = 1;

	m_LightSources.push_back(pair<Matrix3D,bool>(Light0,false));
	m_LightSourcesIntensity.push_back(Matrix3D());

	m_bNormalSwitchDirection = false;
}


CChildView::~CChildView()
{
}


BEGIN_MESSAGE_MAP(CChildView,CWnd )
	//{{AFX_MSG_MAP(CChildView)
	ON_WM_PAINT()
	ON_COMMAND(ID_FILE_LOAD, OnFileLoad)
	ON_COMMAND(ID_AXIS_X, OnAxisX)
	ON_UPDATE_COMMAND_UI(ID_AXIS_X, OnUpdateAxisX)
	ON_COMMAND(ID_AXIS_Y, OnAxisY)
	ON_UPDATE_COMMAND_UI(ID_AXIS_Y, OnUpdateAxisY)
	ON_COMMAND(ID_AXIS_Z, OnAxisZ)
	ON_UPDATE_COMMAND_UI(ID_AXIS_Z, OnUpdateAxisZ)
	ON_COMMAND(ID_ACTION_ROTATE, OnActionRotate)
	ON_UPDATE_COMMAND_UI(ID_ACTION_ROTATE, OnUpdateActionRotate)
	ON_COMMAND(ID_ACTION_SCALE, OnActionScale)
	ON_UPDATE_COMMAND_UI(ID_ACTION_SCALE, OnUpdateActionScale)
	ON_COMMAND(ID_ACTION_TRANSLATE, OnActionTranslate)
	ON_UPDATE_COMMAND_UI(ID_ACTION_TRANSLATE, OnUpdateActionTranslate)
	ON_COMMAND(ID_VIEW_ORTHOGRAPHIC, OnViewOrthographic)
	ON_UPDATE_COMMAND_UI(ID_VIEW_ORTHOGRAPHIC, OnUpdateViewOrthographic)
	ON_COMMAND(ID_VIEW_PERSPECTIVE, OnViewPerspective)
	ON_UPDATE_COMMAND_UI(ID_VIEW_PERSPECTIVE, OnUpdateViewPerspective)
	ON_COMMAND(ID_OPTIONS_BACKFACECULLING, OnOptionsBackfaceculling)
	ON_UPDATE_COMMAND_UI(ID_OPTIONS_BACKFACECULLING, OnUpdateOptionsBackfaceculling)
	ON_COMMAND(ID_OPTIONS_BACKGROUND, OnOptionsBackground)
	ON_UPDATE_COMMAND_UI(ID_OPTIONS_BACKGROUND, OnUpdateOptionsBackground)
	ON_COMMAND(ID_RENDER_GO, OnRenderGo)
	ON_COMMAND(ID_RENDER_SAVE, OnRenderSave)
	ON_COMMAND(ID_LIGHT_SHADING_FLAT, OnLightShadingFlat)
	ON_UPDATE_COMMAND_UI(ID_LIGHT_SHADING_FLAT, OnUpdateLightShadingFlat)
	ON_COMMAND(ID_LIGHT_SHADING_PHONG, OnLightShadingPhong)
	ON_UPDATE_COMMAND_UI(ID_LIGHT_SHADING_PHONG, OnUpdateLightShadingPhong)
	ON_COMMAND(ID_LIGHT_SHADING_GOURAUD, OnLightShadingGouraud)
	ON_UPDATE_COMMAND_UI(ID_LIGHT_SHADING_GOURAUD, OnUpdateLightShadingGouraud)
	ON_COMMAND(ID_LIGHT_CONSTANTS, OnLightConstants)
	ON_COMMAND(ID_LIGHT_DIRECTIONS, OnLightDirections)
	ON_COMMAND(ID_ACTION_RESET, OnReset)
	ON_COMMAND(ID_VIEW_BOUNDINGBOX, &OnViewBoundingbox)
	ON_UPDATE_COMMAND_UI(ID_VIEW_BOUNDINGBOX,OnUpdateViewBoundingbox)
	//}}AFX_MSG_MAP
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()

	
	
	ON_COMMAND(ID_NORMALS_VERTICES, OnNormalsVertices)
	ON_UPDATE_COMMAND_UI(ID_NORMALS_VERTICES, OnUpdateNormalsVertices)
	ON_COMMAND(ID_NORMALS_FACES, OnNormalsFaces)
	ON_UPDATE_COMMAND_UI(ID_NORMALS_FACES, OnUpdateNormalsFaces)
	ON_COMMAND(ID_NORMALS_REVERSE, OnNormalsReverse)
	ON_UPDATE_COMMAND_UI(ID_NORMALS_REVERSE, OnUpdateNormalsReverse)
	ON_WM_ERASEBKGND()
	ON_COMMAND(ID_ADDCURVE_QUADRATIC, OnAddcurveQuadratic)
	ON_COMMAND(ID_ADDCURVE_CUBIC, OnAddcurveCubic)
	ON_COMMAND(ID_ANIMATION_EDITCURVE, OnAnimationEditcurve)
	ON_COMMAND(ID_ANIMATION_REMOVECURVE, OnAnimationRemovecurve)
	ON_COMMAND(ID_VIEW_OCTTREE, OnViewOcttree)
	ON_UPDATE_COMMAND_UI(ID_VIEW_OCTTREE, OnUpdateViewOcttree)
	ON_WM_TIMER()
	ON_COMMAND(ID_ANIMATION_START, OnAnimationStart)
	ON_COMMAND(ID_ANIMATION_END, OnAnimationEnd)
	ON_COMMAND(ID_OPTIONS_SETMOUSESENSETIVITY, &CChildView::OnOptionsSetmousesensetivity)

	ON_COMMAND(ID_OPTIONS_W,OnOptionsW)
	ON_COMMAND(ID_SPACE_WORLD, OnSpaceWorld)
	ON_UPDATE_COMMAND_UI(ID_SPACE_WORLD,OnUpdateSpaceWorld)
	ON_COMMAND(ID_SPACE_OBJECT, OnSpaceObject)
	ON_UPDATE_COMMAND_UI(ID_SPACE_OBJECT,OnUpdateSpaceObject)
	
	ON_COMMAND(ID_VIEW_AXIS,OnViewAxis)
	ON_UPDATE_COMMAND_UI(ID_VIEW_AXIS,OnUpdateViewAxes)
	ON_COMMAND(ID_OPTIONS_SETPROJECTIONPLAIN, &CChildView::OnOptionsSetprojectionplain)
	ON_COMMAND(ID_LIGHTCONSTANTS, &CChildView::OnLightconstants)
	ON_COMMAND(ID_LIGHTSOURCES, &CChildView::OnLightsources)
	ON_COMMAND(ID_NORMALS_SWITCHDIRECTION, &CChildView::OnNormalsSwitchdirection)
	ON_UPDATE_COMMAND_UI(ID_NORMALS_SWITCHDIRECTION,&OnUpdateViewNormalsSwitched)
	
	ON_COMMAND(ID_SHADING_FLAT, &CChildView::OnShadingFlat)
	ON_UPDATE_COMMAND_UI(ID_SHADING_FLAT, &CChildView::OnUpdateShadingFlat)
	ON_COMMAND(ID_SHADING_GOURAUD, &CChildView::OnShadingGouraud)
	ON_UPDATE_COMMAND_UI(ID_SHADING_GOURAUD, &CChildView::OnUpdateShadingGouraud)
	ON_COMMAND(ID_SHADING_PHONG, &CChildView::OnShadingPhong)
	ON_UPDATE_COMMAND_UI(ID_SHADING_PHONG, &CChildView::OnUpdateShadingPhong)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CChildView message handlers


BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) 
{
	if (!CWnd::PreCreateWindow(cs))
		return FALSE;

	cs.dwExStyle |= WS_EX_CLIENTEDGE;
	cs.style &= ~WS_BORDER;
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, 
		::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW+1), NULL);

	return TRUE;
}

void CChildView::OnReset()
{
	m_TransformationMatrix = Matrix3D();
	m_bIsPerspective = false;
	Invalidate();
}

void CChildView::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	dc.SetBkColor(m_iBkgColor);
	CRect rect;
	GetClientRect(&rect);
	CMemDC memDC(&dc);

	if(m_model.IsChanged())
	{
		//starting modifications from scratch
		m_model.reset();

		double dbSize;
		if(rect.Width()< rect.Height())
		{
			dbSize = (rect.Width()+1) / 
					 (m_model.m_dbMaxXcoord-m_model.m_dbMinXcoord);
			cout<<"rect.Width() = "<<rect.Width()<<endl;
		}
		else
		{
			dbSize = (rect.Height()+1) / 
					 (m_model.m_dbMaxYcoord-m_model.m_dbMinYcoord);
			cout<<"rect.Height() = "<<rect.Height()<<endl;
		}

		//Scaling the image to be viewable by the user
		//Rotating Y plane to be point upwards

		Matrix3D Transformations = 
			m_model.TranslateCenterOfMassToOrigin()*
			Matrix3D::ScaleMatrix((1/3.0)*dbSize)*
			Matrix3D::RotateMatrix((4.0*atan(1.0)),ID_AXIS_X)*
			m_TransformationMatrix;


		
		for(unsigned i=0;i<m_LightSources.size();i++)
		{
			if(m_LightSources[i].second == true)
			{
				//the x,y,z is the location of the point light source
				//light source should move with to the center of the screen
				m_LightSources[i].first =
					m_LightSources[i].first*
					m_model.TranslateCenterOfMassToOrigin()*
					Matrix3D::ScaleMatrix((1/3.0)*dbSize)*
					Matrix3D::RotateMatrix((4.0*atan(1.0)),ID_AXIS_X)*
					Matrix3D::TranslateMatrix(
					(rect.Width())/2.0,(rect.Height())/2.0,0);

			}
		}
			
		if(m_bIsPerspective == true)
		{		
			Transformations = 
				Transformations *
				Matrix3D::TranslateMatrix(
					1-(1/3.0)*dbSize*m_model.m_dbMinZcoord
					+CChildView::nMaxProjectionPlane,ID_AXIS_Z)*
				m_PerspectiveMatrix;
		}

		//moving the object to be at the center of the screen
		Transformations = 
			Transformations*
			Matrix3D::TranslateMatrix((rect.Width())/2.0,(rect.Height())/2.0,0);
		
		m_model.MultiplyWithMatrix(Transformations);
		
	}

	m_model.SetColor(m_nWireColor);

	m_model.BackFaceCulling(m_bBackFaceCulling,m_bNormalSwitchDirection);
	
	if(m_bShouldRender == true)
	{	
		m_model.ZBufferScanLine(memDC,
			-10000,
			10000,
			-10000,
			10000,
			-10000,
			10000,
			GetRValue(m_iBkgColor),
			GetGValue(m_iBkgColor),
			GetBValue(m_iBkgColor),
			m_LightSources,
			m_LightSourcesIntensity,
			m_AmbientIntensity);
		m_bShouldRender = false;
	}
	else
	{
		m_model.paint(memDC,m_bDrawBoundingBox,m_bViewAxes,m_bNormalPerFace,m_bNormalPerVertex);
	}

	
	//
	//

	if(m_bViewAxes == true)
	{
		CPen pen(PS_SOLID,3,m_nWireColor);
		CPen *oldPen = memDC.SelectObject(&pen);

		Matrix3D CenterMatrix = m_model.TranslateCenterOfMassToOrigin();

		memDC.MoveTo(rect.Width()/2,0);
		memDC.LineTo(rect.Width()/2,rect.Height());

		memDC.MoveTo(0,rect.Height()/2);
		memDC.LineTo(rect.Width(),rect.Height()/2);

		memDC.SelectObject(oldPen);
	}


	// Add your code here to draw the wireframe (you might want to add a function call)
	// Note: The true size of the CRect is   r.right-r.left+1 or r.Width()+1

	cout << "Draw scene in "
		 << (m_bIsPerspective ? "Perspective" : "Orthographic")
		 << " mode." << endl;
	cout << "Scene size: " << rect.Width()+1 << ", " << rect.Height()+1 << endl;
}



void CChildView::OnFileLoad() 
{
	TCHAR szFilters[] = _T ("VRML2.0 Data Files (*.wrl)|*.wrl|All Files (*.*)|*.*||");
	char *tmpFilename = new char[255];
	
	CFileDialog dlg(TRUE, "wrl", "*.wrl", OFN_FILEMUSTEXIST | OFN_HIDEREADONLY ,szFilters);
	OnReset();
	if (dlg.DoModal () == IDOK) 
	{	
		m_strDataFileName = dlg.GetPathName();		// Keep full path and filename
		
		tmpFilename = (char*)(LPCTSTR)m_strDataFileName;

		// Open Vrml2.0 file and traverse it.
		CallbackObject clbObj_;
		VRNode * root = Vrml2VR(tmpFilename);
		CVRTraverse <CallbackObject> traverseObj_(&clbObj_,
							&CallbackObject::PreTraverseNode,
							&CallbackObject::PostTraverseNode);
		traverseObj_.traverse(root);

		// Here should go the loading of the file to your data structure.
		VRShape **transformedShapes;
		VRDWORD numShapes;
		root->transformShapes(&transformedShapes, numShapes, false);

		m_model.clear();
		OurCallbackObject clbObj(&m_model);
		CVRTraverse <OurCallbackObject> traverseObj(&clbObj,
							&OurCallbackObject::PreTraverseNode,
							&OurCallbackObject::PostTraverseNode);

		for(unsigned int i=0;i<numShapes;i++)
			traverseObj.traverse(transformedShapes[i]);

		OnReset();
		Invalidate();	// force a WM_PAINT for drawing.

		//root->release();
	} 

	//delete[] tmpFilename;
}



// AXIS HANDLERS ///////////////////////////////////////////


// Note: that all the following Message Handlers act in a similar way.
// Each control or command has two functions associated with it.


// Gets calles when the X button is pressed or when the Axis->X menu is selected.
// The only thing we do here is set the ChildView member variable m_nAxis to the 
// selected axis.
void CChildView::OnAxisX() 
{
	m_nAxis = ID_AXIS_X;
}

// Gets called when windows has to repaint either the X button or the Axis pop up menu.
// The control is responsible for its redrawing.
// It sets itself disabled when the action is a Scale action.
// It sets itself Checked if the current axis is the X axis.
void CChildView::OnUpdateAxisX(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(m_nAction != ID_ACTION_SCALE);
	pCmdUI->SetCheck(m_nAxis == ID_AXIS_X);
}


void CChildView::OnAxisY() 
{
	m_nAxis = ID_AXIS_Y;
}


void CChildView::OnUpdateAxisY(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(m_nAction != ID_ACTION_SCALE);
	pCmdUI->SetCheck(m_nAxis == ID_AXIS_Y);
}


void CChildView::OnAxisZ() 
{
	m_nAxis = ID_AXIS_Z;
}

void CChildView::OnUpdateAxisZ(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(m_nAction != ID_ACTION_SCALE);
	pCmdUI->SetCheck(m_nAxis == ID_AXIS_Z);
}




// ACTION HANDLERS ///////////////////////////////////////////

void CChildView::OnActionRotate() 
{
	m_nAction = ID_ACTION_ROTATE;
}

void CChildView::OnUpdateActionRotate(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_nAction == ID_ACTION_ROTATE);
}

void CChildView::OnActionTranslate() 
{
	m_nAction = ID_ACTION_TRANSLATE;
}

void CChildView::OnUpdateActionTranslate(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_nAction == ID_ACTION_TRANSLATE);
}

void CChildView::OnActionScale() 
{
	m_nAction = ID_ACTION_SCALE;
}

void CChildView::OnUpdateActionScale(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_nAction == ID_ACTION_SCALE);
}



// VIEW HANDLERS ///////////////////////////////////////////

void CChildView::OnViewOrthographic() 
{
	m_nView = ID_VIEW_ORTHOGRAPHIC;
	m_bIsPerspective = false;
	Invalidate();		// redraw using the new view.
}

void CChildView::OnUpdateViewOrthographic(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_nView == ID_VIEW_ORTHOGRAPHIC);
}



void CChildView::OnViewPerspective() 
{
	m_nView = ID_VIEW_PERSPECTIVE;
	m_bIsPerspective = true;
	
	Invalidate();
}

void CChildView::OnUpdateViewPerspective(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_nView == ID_VIEW_PERSPECTIVE);

}



// OPTIONS HANDLERS ///////////////////////////////////////////


void CChildView::OnOptionsBackfaceculling() 
{
	m_bBackFaceCulling = (m_bBackFaceCulling ? false : true);
	Invalidate();
}

void CChildView::OnUpdateOptionsBackfaceculling(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_bBackFaceCulling);
}



void CChildView::OnOptionsBackground() 
{
	/*if (m_bBackgroundImage) {	// if active, cancel it
		m_bBackgroundImage = false;
	} else {		// retrieve image, and check if successful
		TCHAR szFilters[] = _T ("BMP Image Files (*.bmp)|*.bmp|All Files (*.*)|*.*||");

		CFileDialog dlg(TRUE, "bmp", "*.bmp", OFN_FILEMUSTEXIST | OFN_HIDEREADONLY ,szFilters);

		if (dlg.DoModal () == IDOK) {		// display modal window
			m_strBmpFileName = dlg.GetPathName();		// Get full path and filename
			// Use this name when rendering. Open it and read it.

			m_bBackgroundImage = true;
		} 
	}*/
	
	CColorDialog dlg(m_iBkgColor);
	if (dlg.DoModal () == IDOK) {		// display modal window
		m_iBkgColor = dlg.m_cc.rgbResult;
	}
	Invalidate();

}

void CChildView::OnUpdateOptionsBackground(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_bBackgroundImage);
}



// RENDER HANDLERS ///////////////////////////////////////////

void CChildView::OnRenderGo() 
{
	m_bShouldRender = true;
	Invalidate();
}


void CChildView::OnRenderSave() 
{
    
    	CRect rect;
	GetClientRect(&rect);

	renderToFile dlg;
	// Set initial dialog parameters
	dlg.m_nHeight = rect.bottom - rect.top + 1;
	dlg.m_nWidth = rect.right - rect.left + 1;
	dlg.m_bUseWinDim = true;

	if (dlg.DoModal() == IDOK) {
		// The user clicked OK
		TCHAR szFilters[] = _T ("PNG Image Files (*.png)|*.png|All Files (*.*)|*.*||");

		CFileDialog fileNameDlg(FALSE, "png", "*.png", OFN_FILEMUSTEXIST | OFN_HIDEREADONLY ,szFilters);

		if (fileNameDlg.DoModal () == IDOK) {
			m_strSaveRenderToFileName = fileNameDlg.GetPathName(); 	// get full file name and path

			// obtain the dimentions that the user entered
			if (dlg.m_bUseWinDim) {
				m_nRenderToFile_Height = rect.bottom - rect.top + 1;
				m_nRenderToFile_Width = rect.right - rect.left + 1;
			} else {
				m_nRenderToFile_Height = dlg.m_nHeight;
				m_nRenderToFile_Width = dlg.m_nWidth;
			}

			cout << "save at " << m_nRenderToFile_Width << "x" << m_nRenderToFile_Height << endl;

			// add code for rendering the image as a png file.
			// m_strSaveRenderToFileName holds the file name
			
			//Demo for the use of pngLib
			PngWrapper pngWrite((char*)(LPCTSTR)m_strSaveRenderToFileName,
					    m_nRenderToFile_Width,
					    m_nRenderToFile_Height);
			pngWrite.InitWritePng();
			for(int i=0;i<m_nRenderToFile_Width;i++)
			    for(int j=0;j<m_nRenderToFile_Height;j++){
				pngWrite.SetValue(i,j,SET_RGB(255,255,0));
			     }
			pngWrite.WritePng();


		} 
	}
	
}



// LIGHT SHADING HANDLERS ///////////////////////////////////////////

void CChildView::OnLightShadingFlat() 
{
	m_nLightShading = ID_LIGHT_SHADING_FLAT;
}

void CChildView::OnUpdateLightShadingFlat(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_nLightShading == ID_LIGHT_SHADING_FLAT);
}


void CChildView::OnLightShadingGouraud() 
{
	m_nLightShading = ID_LIGHT_SHADING_GOURAUD;
}

void CChildView::OnUpdateLightShadingGouraud(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_nLightShading == ID_LIGHT_SHADING_GOURAUD);
}

void CChildView::OnLightShadingPhong() 
{
	m_nLightShading = ID_LIGHT_SHADING_PHONG;
}

void CChildView::OnUpdateLightShadingPhong(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_nLightShading == ID_LIGHT_SHADING_PHONG);
}



// LIGHT CONSTANTS HANDLER ///////////////////////////////////////////

void CChildView::OnLightConstants() 
{
	CMaterialPropertiesDlg dlg;
	// pass current values
	dlg.m_strAmbient.Format("%.2lf", m_lMaterialAmbient);
	dlg.m_strDiffuse.Format("%.2lf", m_lMaterialDiffuse);
	dlg.m_strSpecular.Format("%.2lf", m_lMaterialSpecular);
	dlg.m_nMaterialCosineFactor = m_nMaterialCosineFactor;

	if (dlg.DoModal() == IDOK) {
		// set new current values
		m_lMaterialAmbient = atof(dlg.m_strAmbient);
		m_lMaterialDiffuse = atof(dlg.m_strDiffuse);
		m_lMaterialSpecular = atof(dlg.m_strSpecular);
		m_nMaterialCosineFactor = dlg.m_nMaterialCosineFactor;
	}
}


// LIGHT DIRECTION HANDLER ///////////////////////////////////////////

void CChildView::OnLightDirections() 
{
	CLightDirectionDlg dlg;
	// pass current values
	dlg.m_nDirectionX = m_nArrLightDirection[0];
	dlg.m_nDirectionY = m_nArrLightDirection[1];
	dlg.m_nDirectionZ = m_nArrLightDirection[2];

	if (dlg.DoModal() == IDOK) {
		// set new current values
		m_nArrLightDirection[0] = dlg.m_nDirectionX;
		m_nArrLightDirection[1] = dlg.m_nDirectionY;
		m_nArrLightDirection[2] = dlg.m_nDirectionZ;
	}
}


// MOUSE HANDLERS ///////////////////////////////////////////


void CChildView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	SetCapture();	// capture the mouse 'left button up' command
	m_nXCoord = point.x;		// keep x coordinate
	m_nYCoord = point.y;		// keep y coordinate
}


void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
	CString str;			// create and prepare string
	CMainFrame* pMF = (CMainFrame*)GetParentFrame();	// get Parent Main Frame

	if (GetCapture() == this) {		// 'this' has the mouse capture	
		// This is the movement ammount 
		str.Format("X,Y: %d,%d", point.x - m_nXCoord, point.y - m_nYCoord);
		pMF->getStatusBar().SetPaneText(0,str);		// get the Status Bar and place text

		switch(m_nAction) {			// act based on the current action
		case ID_ACTION_ROTATE:		rotate(point.x - m_nXCoord);	break;
		case ID_ACTION_TRANSLATE:	translate(point.x - m_nXCoord, point.y - m_nYCoord);	break;
		case ID_ACTION_SCALE:		scale(point.x - m_nXCoord);		break;
		}
		Invalidate();					// redraw scene
		m_nXCoord = point.x;			// keep new point
		m_nYCoord = point.y;			// keep new point
	} else {						// 'this' doesn't have the mouse capture (most cases)
		str.Format("%d, %d", point.x, point.y);
		pMF->getStatusBar().SetPaneText(0,str);		// get the Status Bar and put text
	}
}


void CChildView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// if 'this' has the mouse capture, release it.
	if (GetCapture() == this) ::ReleaseCapture();
}




// ACTION FUNCTIONS ///////////////////////////////////////////

void CChildView::rotate(int nValue) {
  CString strAxes ="XYZ";
  cout << "Rotate round " << strAxes.GetAt(m_nAxis - ID_AXIS_X) << " axis: " << nValue << endl;
  
  Matrix3D Rotate;
  double dbAngle = (8.0*atan(1.0))*m_dbMouseSensetivity*nValue;

  /*if(m_bIsObjectSpace == false)
  {
	  m_WorldRotationMatrix = 
		  m_WorldRotationMatrix*Matrix3D::RotateMatrix(dbAngle,m_nAxis);
  }
  else
  {
	 Matrix3D ToCenter = m_model.TranslateCenterOfMassToOrigin();
	 Matrix3D FromCenter = ToCenter;
	 FromCenter[3][0] = -FromCenter[3][0];
	 FromCenter[3][1] = -FromCenter[3][1];
	 FromCenter[3][2] = -FromCenter[3][2];
	 
	 m_ObjectRotationMatrix =
		 ToCenter * Matrix3D::RotateMatrix(dbAngle,m_nAxis) * FromCenter *
		 m_ObjectRotationMatrix;
	 
  }*/
  if(m_bIsObjectSpace == false)
  {
	  m_TransformationMatrix = 
		  m_TransformationMatrix*Matrix3D::RotateMatrix(dbAngle,m_nAxis);
  }
  else
  {
	  m_TransformationMatrix = 
		  Matrix3D::RotateMatrix(dbAngle,m_nAxis)*m_TransformationMatrix;
  }
}

void CChildView::translate(int nXValue, int nYValue) {
  CString strAxes ="XYZ";
  cout << "Translate along " << strAxes.GetAt(m_nAxis - ID_AXIS_X) << " plane: " << nXValue << "," << nYValue  << endl;

  double dbT = nXValue*m_dbMouseSensetivity;

  /*m_TranslateMatrix = 
	  m_TranslateMatrix * 
	  Matrix3D::TranslateMatrix(
					  dbT,
					  m_nAxis);*/
  if(m_bIsObjectSpace == false)
  {
	  m_TransformationMatrix = 
		  m_TransformationMatrix * Matrix3D::TranslateMatrix(dbT,m_nAxis);
  }
  else
  {
	  m_TransformationMatrix =
		 Matrix3D::TranslateMatrix(dbT,m_nAxis) * m_TransformationMatrix;
  }
}


void CChildView::scale(int nValue) {
	cout << "Scale: " << nValue << endl;

	if(nValue == 0 )
		return;
	
	double dbScale = 0.0;
	if(0.1*nValue*m_dbMouseSensetivity < -1)
	{
		dbScale = 0.2;
	}
	else
	{
		dbScale = 1 + 0.1*nValue*m_dbMouseSensetivity;
	}
	//m_ScaleMatrix = m_ScaleMatrix * Matrix3D::ScaleMatrix(dbScale);
	if(m_bIsObjectSpace == false)
	{
		m_TransformationMatrix = 
				m_TransformationMatrix * Matrix3D::ScaleMatrix(dbScale);
	}
	else
	{
		m_TransformationMatrix =
				Matrix3D::ScaleMatrix(dbScale) * m_TransformationMatrix;
	}
}

void CChildView::OnNormalsVertices()
{
	// TODO: Add your command handler code here
	m_bNormalPerVertex = !m_bNormalPerVertex;
	Invalidate();

}

void CChildView::OnUpdateNormalsVertices(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->SetCheck(m_bNormalPerVertex);
}

void CChildView::OnNormalsFaces()
{
	// TODO: Add your command handler code here
	m_bNormalPerFace = !m_bNormalPerFace; 
	Invalidate();
}

void CChildView::OnUpdateNormalsFaces(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->SetCheck(m_bNormalPerFace);
}

void CChildView::OnNormalsReverse()
{
	// TODO: Add your command handler code here
	m_bNormalReverse = !m_bNormalReverse;
}

void CChildView::OnUpdateNormalsReverse(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->SetCheck(m_bNormalReverse);
}

BOOL CChildView::OnEraseBkgnd(CDC* pDC)
{
	// TODO: Add your message handler code here and/or call default

	return FALSE;
}


/*
Set the octtree view option  - on and off
to be used in exercise #3

*/

void CChildView::OnViewOcttree()
{
	// TODO: Add your command handler code here
	m_viewOctTree = !m_viewOctTree;
}

void CChildView::OnUpdateViewOcttree(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->SetCheck(m_viewOctTree);
}


// Basic animation support 

// callbacks to set proper animation curve - 
//you will have to manage the database of curves and select 
//between different curves if you have multiple 
//objects in the scene. 
void CChildView::OnAddcurveQuadratic()
{
	// TODO: Add your command handler code here
	// the editor will start with three points to 
	//edit all with zero components
   //Start the editor for quadratic curves
	//CBezierEditor dlg(NULL,2);
	//dlg.DoModal();
}

void CChildView::OnAddcurveCubic()
{
	// TODO: Add your command handler code here
	//Set the editor for cubic curves
	//CBezierEditor dlg(NULL,3);
	//dlg.DoModal();
}
// edit an existing curve - 
//first Set the current controlpoints then 
//edit them.
void CChildView::OnAnimationEditcurve()
{
	// TODO: Add your command handler code here

	//check the degree of the current curve before 
	//you construct the editor for it
}

void CChildView::OnAnimationRemovecurve()
{
	// TODO: Add your command handler code here

	//remove the current curve from your database
}


// The Callback OnTimer is called every time an WM_TIMER event reaches the
// event loop
// you can select between multiple events based on nIDEvent

void CChildView::OnTimer(UINT nIDEvent)
{
	// TODO: Add your message handler code here and/or call default
	
	CWnd::OnTimer(nIDEvent);
}

// Set a timer that fires every 100 miliseconds
// After this timer was set the OnTimer Function will be called
//periodically


void CChildView::OnAnimationStart()
{
	// TODO: Add your command handler code here
	//timer fires every 100 miliseconds
	this->SetTimer(0,100,NULL);
}
//remove the timer - Here we use win32 API
//KillTimer directly so we have to give it the 
//proper window handle so it can asociate the 
//timer (0) with this handle.
void CChildView::OnAnimationEnd()
{
	// TODO: Add your command handler code here
	::KillTimer(this->m_hWnd,0);
}

void CChildView::OnOptionsSetmousesensetivity()
{
	static double change_speed = 10;

	CSensDialog dlg;
	dlg.m_Sensitivity = (m_dbMouseSensetivity - 0.1)*100.0/change_speed;
	if (dlg.DoModal () == IDOK)
		m_dbMouseSensetivity = 0.1 + change_speed * (dlg.m_Sensitivity / 100.0);
}

void CChildView::OnViewBoundingbox()
{
	m_bDrawBoundingBox = !m_bDrawBoundingBox;
	Invalidate();
}
void CChildView::OnUpdateViewBoundingbox(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_bDrawBoundingBox == true);
}
void CChildView::OnOptionsW()
{
	CColorDialog dlg(m_nWireColor);
	if (dlg.DoModal () == IDOK) {		// display modal window
		m_nWireColor = dlg.m_cc.rgbResult;
	}
	Invalidate();
}

void CChildView::OnSpaceWorld()
{
	m_bIsObjectSpace = false;
}

void CChildView::OnUpdateSpaceWorld(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_bIsObjectSpace == false);
}

void CChildView::OnSpaceObject()
{
	m_bIsObjectSpace = true;
}

void CChildView::OnUpdateSpaceObject(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_bIsObjectSpace == true);
}

void CChildView::OnViewAxis()
{
	m_bViewAxes = !m_bViewAxes;
	Invalidate();
}
void CChildView::OnUpdateViewAxes(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_bViewAxes == true);
}

void CChildView::OnOptionsSetprojectionplain()
{
	ProjectionPlainDialog dlg;

	dlg.m_ProjectionPlain = (double)(m_nProjectionPlane - nMinProjectionPlane)/(nMaxProjectionPlane - nMinProjectionPlane)*100;
	
	if (dlg.DoModal () == IDOK) {
		m_nProjectionPlane = nMinProjectionPlane + ( (double) dlg.m_ProjectionPlain / 100.0) * (nMaxProjectionPlane - nMinProjectionPlane);
		m_PerspectiveMatrix[2][3] = 1.0/m_nProjectionPlane;
		Invalidate();
	}
}

void CChildView::OnLightconstants()
{
	MatPropsDlg dlg;

	

	// parametres that require init: (whose values we later need)
	dlg.ambient = m_model.GetAmbientFactor();
	dlg.diffuse = m_model.GetDiffuseFactor();
	dlg.specular = m_model.GetSpecularFactor();
	dlg.cosine = m_model.GetCosineFactor();

	if (dlg.DoModal () == IDOK) {
		
		m_model.SetAmbientFactor(dlg.ambient);
		m_model.SetDiffuseFactor(dlg.diffuse);
		m_model.SetSpecularFactor(dlg.specular);
		m_model.SetCosineFactor(dlg.cosine);
	}
}

void CChildView::OnLightsources()
{
	LightSourcesDlg dlg;

	dlg.m_ambient_r = m_AmbientIntensity[0][0]*255;
	dlg.m_ambient_g = m_AmbientIntensity[1][1]*255;
	dlg.m_ambient_b = m_AmbientIntensity[2][2]*255;
	
	// the list of lights doesnt require init (it saves em by itself) so just read the values
	// after the OK button has been pressed. example follows
	if (dlg.DoModal () == IDOK) 
	{
		m_AmbientIntensity[0][0] = (dlg.m_ambient_r/255.0);
		m_AmbientIntensity[1][1] = (dlg.m_ambient_g/255.0);
		m_AmbientIntensity[2][2] = (dlg.m_ambient_b/255.0);
		m_LightSources.clear();
		m_LightSourcesIntensity.clear();
		for (unsigned i(0) ; i < dlg.num_of_lights ; ++i)
		{
			if(dlg.m_lights[i].enabled == false)
			{
				continue;
			}
			Matrix3D direction(1,4,true);
			direction[0][0] = dlg.m_lights[i].x;
			direction[0][1] = dlg.m_lights[i].y;
			direction[0][2] = dlg.m_lights[i].z;
			direction[0][3] = 1;
			Matrix3D intensity;
			intensity[0][0] =  dlg.m_lights[i].r/255.0;
			intensity[1][1] =  dlg.m_lights[i].g/255.0;
			intensity[2][2] =  dlg.m_lights[i].b/255.0;
			m_LightSourcesIntensity.push_back(intensity);

			if(dlg.m_lights[i].point == true)
			{
				m_LightSources.push_back(pair<Matrix3D,bool>(direction,true));
			}
			else
			{
				m_LightSources.push_back(pair<Matrix3D,bool>(direction,false));
			}
		}
	}
}

void CChildView::OnNormalsSwitchdirection()
{
	m_bNormalSwitchDirection = !m_bNormalSwitchDirection;
	Invalidate();
}

void CChildView::OnUpdateViewNormalsSwitched(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_bNormalSwitchDirection == true);
}
void CChildView::OnShadingFlat()
{
	m_model.SetShadingMethod(OurModel::FLAT);
}

void CChildView::OnUpdateShadingFlat(CCmdUI *pCmdUI)
{
	pCmdUI->SetCheck(m_model.GetShadingMethod() == OurModel::FLAT);
}

void CChildView::OnShadingGouraud()
{
	m_model.SetShadingMethod(OurModel::GOURAUD);
}

void CChildView::OnUpdateShadingGouraud(CCmdUI *pCmdUI)
{
	pCmdUI->SetCheck(m_model.GetShadingMethod() == OurModel::GOURAUD);
}

void CChildView::OnShadingPhong()
{
	m_model.SetShadingMethod(OurModel::PHONG);
}

void CChildView::OnUpdateShadingPhong(CCmdUI *pCmdUI)
{
	pCmdUI->SetCheck(m_model.GetShadingMethod() == OurModel::PHONG);
}
